/******************************************************************************
** 公司名称：天津柯迪斯科技有限公司
** 版权信息：
** 文件名称： App_Protocol_LiShui_Uart.c
** 模块名称： LiShui_Uart协议处理模块
** 版 本 号： V1.0
** 作    者： ZRT
**
** 修改记录： 版本     修改人      时间         修改内容
******************************************************************************/

/******************************************************************************
* 头文件
******************************************************************************/
#include <string.h>
#include "Config.h"
#include "App_Protocol.h"
#include "App_MainTask.h"
#include "App_Parameter.h"
/******************************************************************************
* 本文件宏定义 ('#define')
******************************************************************************/
#define FRAME_LEN_MAX		100		/*最大帧长度*/
#define LOOP_CYCLE          25      /*Loop函数轮询周期，单位ms*/
/******************************************************************************
* 本文件类型定义 ('typedef')
******************************************************************************/

/******************************************************************************
* 本文件静态函数声明 ('static')
******************************************************************************/
static void vPROTOCOL_Factory_Command(void);
static void vPROTOCOL_Factory_Response(uint8_t Cmd, uint16_t Response);
 
static void vPROTOCOL_Get_Data_LiShui_Uart(void);
static void vPROTOCOL_Send_LiShui_Uart(void);
static void vPROTOCOL_Get_Data_LiShui_Para(void);
static void vPROTOCOL_Read_Firmware_Part_Number(void);
/******************************************************************************
* 全局变量定义
******************************************************************************/
uint8_t gucRx_Buffer[FRAME_LEN_MAX] = {0};
uint8_t gucTx_Buffer[FRAME_LEN_MAX] = {0};
uint8_t 					gucRx_Frame_OK 	= 0;
uint16_t 					gusRx_Len 		= 0;
stRECEIVED_DATA			gtReceived_Data 	= {0};
stSEND_DATA				gtSend_Data			= {0};
enSEND_DATA_TYPE		geSend_Data_Type 	= Send_Stop;
uint8_t					gucTimeOutError 	= 0;
uint32_t                gulCommunicationCnt = 0;
uint8_t                 gucReceivedConfigFrame = 0;  /*是否已接收到配置帧标记*/
uint32_t                 gulReceivedRunFrame = 0;     /*是否已接收到运行帧标记*/
uint8_t                 gucRequestSendConfigData = 0;/*请求发送配置帧标记*/
uint8_t                 gucReceivedReadFrame = 0;    /*是否已接收到读应答帧标记*/
uint8_t                 SOC_Cnt = 9;                 /*未接收到SOC通信时间计数*/
uint8_t                 gucStartReceive = 0;         /*是否开始接收标志*/
uint8_t                 gucReceiveCnt = 0;			 /*接收计数*/

extern uint8_t gulIsInSetting ;	/*设置状态标志*/

uint16_t    gusParaAddrTable[] =
{
//    0x8A06,
    0x8000,    
    0x8001,    
    0x8002,    
    0x8003,    
    0x8004,  
    0x8005,      
    0x891D,   
    0x891E,
};
static uint8_t gucParaReadOnCnt = 0;
static uint8_t Run_Read_Flag = 0;
static uint16_t luVerAddr = 0x8A05;
static uint8_t luRead_Ver_flag = 0;
/*****************************************************************************
* 函数实现 - global ('extern') and local ('static')
******************************************************************************/

/******************************************************************************
** 功  能：获取一帧协议数据
** 参  数：pData-指向数据的指针，Len-数据长度
** 返回值：无
** 备  注：该函数是协议处理模块对外获取数据的接口，接收到完整一帧后，调用该函数进行处理
******************************************************************************/
void vPROTOCOL_Get_OneFrame(uint8_t *pData, uint16_t Len)
{
    if(Len > 1)		/*如果接收到的数据大于1字节，认为是一个完整帧（DMA+IDLE中断接收），直接放入缓存进行处理*/
	{
		memcpy(gucRx_Buffer,pData,Len);		/*将数据拷贝到缓冲区*/
		gusRx_Len = Len;					/*数据长度*/
		gucRx_Frame_OK = 1;					/*接收到一帧标志置1*/
	}
	else	/*如果只接收到1个字节，认为控制器是按照单个字节发送，则利用帧间超时来判断一帧接收完毕*/
	{
		if(gucStartReceive == 0)
		{
			gucStartReceive = 1;		/*标记开始接收*/
			gucReceiveCnt = 0;
		}
		gucRx_Buffer[gucReceiveCnt] = *pData;
		if(++gucReceiveCnt > FRAME_LEN_MAX)
		{
			gucReceiveCnt = 0;
			gucStartReceive = 0;
		}
	}
}

/******************************************************************************
** 功  能：解析协议数据
** 参  数：无
** 返回值：无
** 备  注：该函数在主函数中被循环调用。用于解析接收到的协议数据
******************************************************************************/
void vPROTOCOL_Loop(void)
{
    static uint32_t lusCnt = 0;
    static uint8_t  lucReceiveCnt = 0;	/*用于保存上一次的接收计数*/

    if(gucRx_Frame_OK == 1)
    {
        gulCommunicationCnt = ulBsp_Getticks();
        gucTimeOutError = 0;
        if(gucRx_Buffer[0] == 0x3A && gucRx_Buffer[1] == 0x1C)
        {
            /*内部控制指令*/
            vPROTOCOL_Factory_Command();
        }
        else if(gucRx_Buffer[0] == 0x3A && ((gucRx_Buffer[1] & 0x50) == 0x50) )
        {
            /*调用加密读写参数协议进行解析*/
            vPROTOCOL_Get_Data_LiShui_Para();
        }
        else
        {
            /*调用不同的协议进行解析*/
            vPROTOCOL_Get_Data_LiShui_Uart();
        }
        gucRx_Frame_OK = 0;
    }
    else
    {
        /*帧间超时判断*/
        if(gucStartReceive == 1)
		{
			if((gucReceiveCnt > 0) && (gucReceiveCnt == lucReceiveCnt))
			{
				gucStartReceive = 0;
				gusRx_Len = gucReceiveCnt;
				gucRx_Frame_OK = 1;
			}
			else
			{
				lucReceiveCnt = gucReceiveCnt;
			}
		}
		else
		{
		}
#if (DEBUG == 0)        
        /*当发送状态为停止时，不报通讯超时错误*/
        if(geSend_Data_Type != Send_Stop)
        {
            /*通讯超时时间，10s*/
            if(ulBsp_Getticks() - gulCommunicationCnt > 2600)
            {
                gucTimeOutError = 1;
                gtReceived_Data.Speed_0_1Km = 0;  /*确保返回的速度值为0*/
            }
        }
        else
#endif        
        {
            gucTimeOutError = 0;
            gulCommunicationCnt = ulBsp_Getticks();
        }
    }
    
    
    lusCnt++;
    
    
    if(lusCnt > (1000/ LOOP_CYCLE))/*控制器通电后前两秒 不会回复仪表报文，所以等待1s 后再发送*/
    {
        if(lusCnt % (50 / LOOP_CYCLE) == 0)
        {

            if(luRead_Ver_flag == 1)
            {
                vPROTOCOL_Read_Firmware_Part_Number();/*轮询读取固件零件号*/
                return;/*避免和下面的协议发送报文黏连*/
            }
            else
            {
                if(geSend_Data_Type == Send_Parameter_Data_Read )/*读取参数时快一点*/
                {
                    vPROTOCOL_Send_LiShui_Uart();
                }
            }     
        }
        
        /*250ms发送一次数据。根据Loop函数的调用周期，计算次数*/
        if(lusCnt % (250 / LOOP_CYCLE) == 0)
        {
            if(geSend_Data_Type != Send_Parameter_Data_Read )
            {
                vPROTOCOL_Send_LiShui_Uart();
            }
            if(SOC_Cnt < 10)
            {
                SOC_Cnt++;
            }
        }
    }

}

/******************************************************************************
** 功  能：设置大灯状态
** 参  数：State-大灯状态。0-关闭，1-打开
** 返回值：无
** 备  注：所有协议通用
******************************************************************************/
void vPROTOCOL_Set_Lamp(uint8_t State)
{
    gtSend_Data.Lamp = State == 0 ? 0 : 1;
}

/******************************************************************************
** 功  能：设置大灯状态
** 参  数：State-大灯状态。0-关闭，1-打开
** 返回值：无
** 备  注：所有协议通用
******************************************************************************/
void vPROTOCOL_Set_Turn_Light(uint8_t turn)
{
    gtSend_Data.Turn_Light_Left = turn == 0x01 ? 1 : 0;

    gtSend_Data.Turn_Light_Right = turn == 0x02 ? 1 : 0;
}

/******************************************************************************
** 功  能：设置档位
** 参  数：Pas-档位值，最大为9，最小为-1,-1表示助推档
** 返回值：无
** 备  注：本函数不对档位值的合理性做检查。请保证传入的档位值正确。
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Set_Pas(int8_t Pas)
{
    if(Pas > 0)
    {
        gtSend_Data.Push = 0;
        gtSend_Data.Pas = Pas;
        if(gtParam.Pas_Max == 3 && Pas < 4)
        {
            gtSend_Data.Max_PWM = 255 * gtParam.PWM0_3[Pas - 1] / 100;
        }
        else if(gtParam.Pas_Max == 5 && Pas < 6)
        {
            gtSend_Data.Max_PWM = 255 * gtParam.PWM0_5[Pas - 1] / 100;
        }
        else if(gtParam.Pas_Max == 7 && Pas < 8)
        {
            gtSend_Data.Max_PWM = 255 * gtParam.PWM0_7[Pas - 1] / 100;
        }
        else if(gtParam.Pas_Max == 9 && Pas < 10)
        {
            gtSend_Data.Max_PWM = 255 * gtParam.PWM0_9[Pas - 1] / 100;
        }
    }
    else if(Pas == 0)
    {
        gtSend_Data.Push = 0;
        gtSend_Data.Pas = 0;
        gtSend_Data.Max_PWM = 0;
    }
    else
    {
        gtSend_Data.Push = 1;
    }
}

/******************************************************************************
** 功  能：设置限速值 单位 km/h
** 参  数：Speed-限速值 同时给转把限速和助力限速赋值
** 返回值：无
** 备  注：本函数不对传入值的合理性做检查。请保证传入的值正确。
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Set_Speed_Limit(uint16_t Speed)
{
    gtSend_Data.Speed_Limit_Assist = Speed;

}

/******************************************************************************
** 功  能：设置转把限速值 单位 km/h
** 参  数：Speed-限速值 同时给转把限速和助力限速赋值
** 返回值：无
** 备  注：本函数不对传入值的合理性做检查。请保证传入的值正确。
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Set_Handle_Speed_Limit(uint16_t Speed)
{
    gtSend_Data.Speed_Limit_Handle = Speed;
}
/******************************************************************************
** 功  能：设置轮径（转换为mm）
** 参  数：Wheel-轮径值 英寸*10
** 返回值：无
** 备  注：本函数不对传入值的合理性做检查。请保证传入的值正确。
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Set_Wheel(uint16_t Wheel)
{
    if(Wheel == 220)
    {
        gtSend_Data.Wheel_Diameter = 563;
    }
    else
    {
        gtSend_Data.Wheel_Diameter = Wheel * 254 / 10 / 10;
    }
}

/******************************************************************************
** 功  能：设置欠压标志
** 参  数：Battery_Low-欠压标志，0-不欠压，1-欠压
** 返回值：无
** 备  注：本函数不对传入值的合理性做检查。请保证传入的值正确。
** 适用协议：5S
******************************************************************************/
void vPROTOCOL_Set_Battery_Low(uint8_t Battery_Low)
{
    gtSend_Data.Battery_Low = Battery_Low == 0 ? 0 : 1;
}

/******************************************************************************
** 功  能：设置助力方向
** 参  数：Assistant_Dir-助力方向，0-正向，1-反向
** 返回值：无
** 备  注：
** 适用协议：5S
******************************************************************************/
void vPROTOCOL_Set_Assistant_Dir(uint8_t Assistant_Dir)
{
    gtSend_Data.Assistant_Dir = Assistant_Dir == 0 ? 0 : 1;
}

/******************************************************************************
** 功  能：设置助力磁钢数
** 参  数：Assistant_Num-助力磁钢数
** 返回值：无
** 备  注：
** 适用协议：5S
******************************************************************************/
void vPROTOCOL_Set_Assistant_Num(uint8_t Assistant_Num)
{
    gtSend_Data.Assistant_Num = Assistant_Num;
}

/******************************************************************************
** 功  能：设置助力灵敏度（助力过几个磁钢开始）
** 参  数：Assistant_Sensitivity-助力灵敏度
** 返回值：无
** 备  注：
** 适用协议：5S
******************************************************************************/
void vPROTOCOL_Set_Assistant_Sensitivity(uint8_t Assistant_Sensitivity)
{
    if(Assistant_Sensitivity > 63)
    {
        Assistant_Sensitivity = 63;     /*设置最大值*/
    }
    if(Assistant_Sensitivity == 0)
    {
        Assistant_Sensitivity = 1;      /*助力灵敏度不能为0*/
    }
    gtSend_Data.Assistant_Sensitivity = Assistant_Sensitivity;
}

/******************************************************************************
** 功  能：设置速度传感器数量
** 参  数：Speed_Sensor_Num-速度传感器数量
** 返回值：无
** 备  注：
** 适用协议：5S
******************************************************************************/
void vPROTOCOL_Set_Speed_Sensor_Num(uint8_t Speed_Sensor_Num)
{
    if(Speed_Sensor_Num > 15)
    {
        Speed_Sensor_Num = 15;
    }
    gtSend_Data.Speed_Sensor_Num = Speed_Sensor_Num;
}

/******************************************************************************
** 功  能：设置启动强度（缓启动参数）
** 参  数：Start_Strength-启动强度
** 返回值：无
** 备  注：
** 适用协议：5S
******************************************************************************/
void vPROTOCOL_Set_Start_Strength(uint8_t Start_Strength)
{
    if(Start_Strength > 3)
    {
        Start_Strength = 3;
    }
    gtSend_Data.Start_Strength = Start_Strength;
}

/******************************************************************************
** 功  能：设置转把是否支持助推
** 参  数：Handle_Push-转把是否支持助推，0-正常转把，1-转把6km助推
** 返回值：无
** 备  注：
** 适用协议：5S
******************************************************************************/
void vPROTOCOL_Set_Handle_Push(uint8_t Handle_Push)
{
    gtSend_Data.Handle_Push = Handle_Push == 0 ? 0 : 1;
}

/******************************************************************************
** 功  能：设置转把是否支持分档
** 参  数：Handle_Segement-转把是否支持分档，0-转把不分档，1-转把分档
** 返回值：无
** 备  注：
** 适用协议：5S
******************************************************************************/
void vPROTOCOL_Set_Handle_Segement(uint8_t Handle_Segement)
{
    gtSend_Data.Handle_Segement = Handle_Segement == 0 ? 0 : 1;
}

/******************************************************************************
** 功  能：设置系统欠压值
** 参  数：Low_Voltage-系统欠压值，分辨率：0.1V
** 返回值：无
** 备  注：
** 适用协议：5S
******************************************************************************/
void vPROTOCOL_Set_Low_Voltage(uint16_t Low_Voltage)
{
    gtSend_Data.Low_Voltage = Low_Voltage;
}

/******************************************************************************
** 功  能：设置系统电压值
** 参  数：Sys_Voltage-系统电压值，分辨率：1V，支持：24V，36V，48V
** 返回值：无
** 备  注：同时设置系统欠压值
** 适用协议：5S
******************************************************************************/
void vPROTOCOL_Set_Sys_Voltage(uint16_t Sys_Voltage)
{
    gtSend_Data.Sys_Voltage = Sys_Voltage;
    if(Sys_Voltage == 36)
    {
        gtSend_Data.Low_Voltage = gtParam.V_36_Tab[0] - 10;
    }
    else if(Sys_Voltage == 48)
    {
        gtSend_Data.Low_Voltage = gtParam.V_48_Tab[0] - 10;
    }
    else if(Sys_Voltage == 52)
    {
        gtSend_Data.Low_Voltage = gtParam.V_52_Tab[0] - 10;
    }
}

/******************************************************************************
** 功  能：设置系统限流值
** 参  数：Current_Limit-系统限流值，分辨率：0.5V
** 返回值：无
** 备  注：
** 适用协议：5S
******************************************************************************/
void vPROTOCOL_Set_Current_Limit(uint16_t Current_Limit)
{
    gtSend_Data.Current_Limit = Current_Limit;
}

/******************************************************************************
** 功  能：设置档位范围
** 参  数：Pas_Range-档位值范围，3，4，5，9
** 返回值：无
** 备  注：J协议不支持档位范围设置，为了兼容其他协议，该函数为空即可。
******************************************************************************/
void vPROTOCOL_Set_Pas_Range(int8_t Pas_Range)
{

}

/******************************************************************************
** 功  能：设置发送运行数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，即开始发送运行数据。直到再次设置发送配置数据或停止
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Send_Run_Data(void)
{
    Run_Read_Flag = 0;
    geSend_Data_Type = Send_Run_Data;
}

/******************************************************************************
** 功  能：发送关机标识数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，即开始发送运行数据。直到再次设置发送配置数据或停止
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Send_Write_Poweroff(void)
{
    geSend_Data_Type = Send_Poweroff_Write;
}

/******************************************************************************
** 功  能：设置发送配置数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，将请求发送配置帧标记置1，当发送完当前运行帧后，即开始发送配置帧
**         目的是在发送配置帧之前，能够将档位变为0
******************************************************************************/
void vPROTOCOL_Send_Config_Data(void)
{
    gucRequestSendConfigData = 1;
}

/******************************************************************************
** 功  能：设置发送一次配置数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，只发送一次配置数据。然后会转为发送运行数据
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Send_Config_Data_OneTime(void)
{
    geSend_Data_Type = Send_Config_Data_OneTime;
    gucReceivedConfigFrame = 0;
}

/******************************************************************************
** 功  能：设置发送一次运行数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，只发送一次运行数据。然后会转为发送配置数据
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Send_Config_RunData_OneTime(void)
{
    gulReceivedRunFrame = 0;
    geSend_Data_Type = Send_Config_RunData_OneTime;
}

/******************************************************************************
** 功  能：设置发送一次配置读取数据
** 参  数：无
** 返回值：无
** 备  注： 
******************************************************************************/
void vPROTOCOL_Send_Read_Data_OneTime(void)
{
    geSend_Data_Type = Send_Parameter_Data_Read;
    gucReceivedReadFrame = 0;
}
/******************************************************************************
** 功  能：停止发送数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，即停止发送数据。直到再次设置发送配置数据或发送运行数据
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Send_Stop(void)
{
    geSend_Data_Type = Send_Stop;
}

/******************************************************************************
** 功  能：获取电池容量
** 参  数：无
** 返回值：-1表示未获取到电池容量，电池容量，0-100%
** 备  注：J协议不支持SOC，返回-1，为了兼容其他协议。
******************************************************************************/
int8_t cPROTOCOL_Get_Soc(void)
{
    if(SOC_Cnt > 9)
    {
        return -1;
    }
    else if(gtReceived_Data.Ctrl_Soc < 100)
    {
        return gtReceived_Data.Ctrl_Soc;
    }
    else
    {
        return 100;
    }
}

/******************************************************************************
** 功  能：获取当前功率值
** 参  数：无
** 返回值：实际功率值
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_Power(void)
{
    if(gucTimeOutError == 1)
    {
        return 0;
    }
    else
    {
        return gtReceived_Data.Power;
    }
}

//uint8_t usPROTOCOL_Get_Unit(void)
//{
//    return gtReceived_Data.Unit;
//}
//uint8_t usPROTOCOL_Get_ClassType(void)
//{
//    return gtReceived_Data.Class_type;
//}
/******************************************************************************
** 功  能：获取当前车速
** 参  数：无
** 返回值：实际车速*10.比如返回120，实际车速即12.0Km/h
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_Speed(void)
{

    return gtReceived_Data.Speed_0_1Km;
}

/******************************************************************************
** 功  能：获取剩余里程
** 参  数：无
** 返回值：实际车速*10.比如返回120，实际车速即12.0Km/h
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_ToGoRange(void)
{
    return gtReceived_Data.Range;
}

/******************************************************************************
** 功  能：获取总里程
** 参  数：无
** 返回值：单位0.1Km
** 备  注：所有协议通用
******************************************************************************/
uint32_t usPROTOCOL_Get_Odo(void)
{
    return gtReceived_Data.Odo;
}

/******************************************************************************
** 功  能：获取错误代码
** 参  数：无
** 返回值：十六进制的错误代码
** 备  注：包括30错误代码（通信超时）
**         所有协议通用
******************************************************************************/
uint16_t ucPROTOCOL_Get_Errcode(void)
{
    if(gucKey_Stucked)// == 1
    {
        return 0x34;
    }
    else if(gucTimeOutError == 1)
    {
        return 0x30;
    }
    else
    {
#if(DEBUG)
        if(gtReceived_Data.ErrCode == 0x26)
        {
            return 0;
        }
#endif   
        if(((gtReceived_Data.ErrCode < 0x20) && (gtReceived_Data.ErrCode >= 0x10)) ||((gtReceived_Data.ErrCode  < 0x27) && (gtReceived_Data.ErrCode  > 0x20)))
        {
                if((gtReceived_Data.ErrCode < 0x20) && (gtReceived_Data.ErrCode >= 0x10))
                {
                    if(gtReceived_Data.ErrCode == 0x11)
                    {
                         return 6;
                    }
                    else if(gtReceived_Data.ErrCode == 0x18)
                    {
                         return 9;
                    }
                    else if(gtReceived_Data.ErrCode == 0x14)
                    {
                         return 0x16;
                    }
                    else if(gtReceived_Data.ErrCode == 0x15)
                    {
                         return 0x26;
                    }
                    else
                    {
                         return gtReceived_Data.ErrCode;
                    }
                }
                else if((gtReceived_Data.ErrCode < 0x26) && (gtReceived_Data.ErrCode >= 0x20))
                {
                     return gtReceived_Data.ErrCode;
                }
                else if(gtReceived_Data.ErrCode == 0x26)
                {

                     return 0x15;
                }
                else if(gtReceived_Data.ErrCode == 0x30)
                {

                     return gtReceived_Data.ErrCode;
                }
                else if(gtReceived_Data.ErrCode == 0x34)
                {

                     return gtReceived_Data.ErrCode;
                }
                else
                {
                     return gtReceived_Data.ErrCode;
                }
            
            return gtReceived_Data.ErrCode;
        }
        else
        {
            return 0;
        }
    }
}

/******************************************************************************
** 功  能：获取控制器硬件代码
** 参  数：无
** 返回值：
** 备  注：溧水 radpower专用
******************************************************************************/
void ucPROTOCOL_Get_HardVer(uint16_t *PverH)
{
    *(PverH)     = gtReceived_Data.HardVer[0];
    *(PverH + 1) = gtReceived_Data.HardVer[1];
}

void ucPROTOCOL_Get_SoftVer(uint16_t *Pvers)
{
#if(DEBUG)  
    *(Pvers)     = 0x0000;
    *(Pvers + 1) = 0xE700; 
    *(Pvers + 2) = 0xF004;
    *(Pvers + 3) = 0x23F1; 
#else    
    *(Pvers)     = gtReceived_Data.SoftVer[0];
    *(Pvers + 1) = gtReceived_Data.SoftVer[1]; 
    *(Pvers + 2) = gtReceived_Data.SoftVer[2];
    *(Pvers + 3) = gtReceived_Data.SoftVer[3]; 
#endif
}

uint16_t  ucPROTOCOL_Get_MCU_Type(void)
{
    return gtReceived_Data.SoftVer[1];
}

/******************************************************************************
** 功  能：获取ClassType 可调上限
** 参  数：无
** 返回值：可调内容
** 备  注： 
******************************************************************************/
uint8_t  ucPROTOCOL_Get_ClassOption_Type(void)
{
 
        return gtReceived_Data.Class_OptionMax;  
}
/******************************************************************************
** 功  能：发送关机数据
** 参  数：无
** 返回值：无
** 备  注：本函数需要100ms调用一次。根据不同的协议，内部自动调节发送周期
******************************************************************************/
void vPROTOCOL_Send(void)
{
    vBsp_DelayMs(50);
    vPROTOCOL_Send_Run_Data();
    vPROTOCOL_Send_LiShui_Uart();

    vBsp_DelayMs(80);

    vPROTOCOL_Send_Write_Poweroff();
    vPROTOCOL_Send_LiShui_Uart();
    vBsp_DelayMs(30);
}

/******************************************************************************
** 功  能：工厂指令的应答
** 参  数：Cmd-要应答的指令，Response-要应答的参数
** 返回值：无
** 备  注：
******************************************************************************/
static void vPROTOCOL_Factory_Response(uint8_t Cmd, uint16_t Response)
{
    uint8_t lucRxBuffer[8];

    /*这个函数会在中断中调用。按说不应该采用这种阻塞延时的方式。但是因为校准指令的发送实际不确定，不加延时，*/
    /*有可能造成应答帧和前后发送数据的正常帧连在一起，造成工装无法识别。因此强制增加了20ms的延时。*/
    /*这个函数只是在工厂校准用。正常使用不会调用。因此阻塞延时对用户使用性能无影响*/

    vBsp_DelayMs(30);
    lucRxBuffer[0] = 0x3A;  /*0x3A,0x50是应答帧的帧头*/
    lucRxBuffer[1] = 0x50;
    lucRxBuffer[2] = Cmd;
    lucRxBuffer[3] = Response & 0x00FF;
    lucRxBuffer[4] = (Response >> 8) & 0x00FF;
    lucRxBuffer[5] = lucRxBuffer[2] + lucRxBuffer[3] + lucRxBuffer[4]; /*8位的和校验*/
    lucRxBuffer[6] = 0x0D;
    lucRxBuffer[7] = 0x0A;  /*0x0D,0x0A是固定帧尾*/

    USART_MCU_Send_Frame(lucRxBuffer, 8);
    vBsp_DelayMs(30);
}

/******************************************************************************
** 功  能：工厂指令的解析
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Factory_Command(void)
{
    uint16_t n;
    uint16_t lusCheckSum = 0;
    uint16_t lusResponse;

    for(n = 0; n < gusRx_Len - 5; n++)
    {
        lusCheckSum += gucRx_Buffer[1 + n];		/*计算校验值，和校验*/
    }
    if((gucRx_Buffer[3] == gusRx_Len - 8) && (lusCheckSum == gucRx_Buffer[gucRx_Buffer[3] + 5] * 256UL + gucRx_Buffer[gucRx_Buffer[3] + 4]))
    {
        switch(gucRx_Buffer[2])
        {
        case 0x5D:		/*电压校准*/
        {
            lusResponse = vVoltage_Calibration();
            vPROTOCOL_Factory_Response(0x5D, lusResponse);
            break;
        }
        case 0x8E:		/*清除ODO*/
        {
            vClear_ODO();
            vPROTOCOL_Factory_Response(0x8E, 5678); /*5678是针对清ODO的固定响应*/
            break;
        }
        case 0x6E:		/*校准光感*/
        {
            lusResponse = vPhotoDiode_Calibration();
            vPROTOCOL_Factory_Response(0x6E, lusResponse);
            break;
        }
        case 0x71:		/*自动校准时间*/
        {
            vDateTime_Calibration(gucRx_Buffer[7], gucRx_Buffer[8], gucRx_Buffer[9], gucRx_Buffer[4], gucRx_Buffer[5], gucRx_Buffer[6]);
            vPROTOCOL_Factory_Response(0x71, 1234); /*1234是针对校准时间的固定响应*/
            break;
        }
        default:
            break;
        }
    }
}

/******************************************************************************
** 功  能：CRC
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
unsigned short int CRC16 ( unsigned char *arr_buff, unsigned int len )
{
    unsigned short int crc = 0xFFFF;
    unsigned int i, j;
    for ( j = 0; j < len; j++)
    {
        crc = crc ^ *arr_buff++;
        for ( i = 0; i < 8; i++)
        {
            if( (crc & 0x0001) > 0)
            {
                crc = crc >> 1;
                crc = crc ^ 0xa001;
            }
            else
            {
                crc = crc >> 1;
            }
        }
    }
    return (crc);
}
static uint8_t Key1, Key2, Key3, Key4;
/******************************************************************************
** 功  能：解析LiShui_Uar协议数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
uint16_t ceshi = 0;
static void vPROTOCOL_Get_Data_LiShui_Para(void)
{
    uint16_t check_num;
    uint16_t Para_Num;
    uint8_t Key_array[2];
    ceshi = check_num = CRC16(gucRx_Buffer, gusRx_Len - 4);

    /*首字节是0x3A，并且校验正确，认为接收数据无误*/
    if((gucRx_Buffer[0] == 0x3A) && (gucRx_Buffer[gusRx_Len - 4] == check_num / 256) && (gucRx_Buffer[gusRx_Len - 3] == check_num % 256))
    {
        if(gucRx_Buffer[1] == 0x51)  /*控制器如果发回S，不解析*/
        {
            Key1 = gucRx_Buffer[2];
            Key2 = gucRx_Buffer[3];
            Key3 = gucRx_Buffer[4];
            Key4 = gucRx_Buffer[5];
            geSend_Data_Type = Send_Parameter_Data_Write;
        }
        else if(gucRx_Buffer[1] == 0x53)
        {
            Key_array[0] = Key1;
            Key_array[1] = Key3;

            Para_Num = (uint16_t)(gucRx_Buffer[2] ^ (CRC16(Key_array, 2) >> 8) ^ 0x7D) << 8;		/*地址高*/
            Para_Num |= gucRx_Buffer[3] ^ (CRC16(Key_array, 2) & 0xFF) ^ 0x9B; /*地址低*/
            if(Para_Num == 0x891D)
                geSend_Data_Type = Send_Parameter_Out;
        }
    }
}
/******************************************************************************
** 功  能：解析LiShui_Uar协议数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
                               /*class    1    2    3     3.25   3.28*/
const uint8_t Speed_Limit_Class[6] =  {0, 32,  32,  32,    40,    45};
const uint8_t Handle_Limit_Class[6] = {0, 0,   32,  32,    32,    32};
static void vPROTOCOL_Get_Data_LiShui_Uart(void)
{
    uint16_t Checksum = 0;
    uint16_t CrcChecksum = 0;    
    uint8_t n;
 
    //    uint16_t lusErr = 0;
    //    const uint8_t Err_Table[15]={0x10,0x11,0x21,0x12,0x24,0x23,0x22,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x25};
    for(n = 0; n < gucRx_Buffer[3] + 3; n++)
    {
        Checksum += gucRx_Buffer[n + 1];	/*计算校验值*/
    }
    /*首字节是0x3A，并且校验正确，认为接收数据无误*/
    if((gucRx_Buffer[0] == 0x3A) && (gucRx_Buffer[gusRx_Len - 4] == Checksum % 256) && (gucRx_Buffer[gusRx_Len - 3] == Checksum / 256))
    {
        if(gucRx_Buffer[2] == 'R')  /*控制器如果发回S，不解析*/
        {
            gulReceivedRunFrame++ ;
            if(SOC_Cnt > 9)
            {
                lucSoc_Smooth = 0;
            }
            SOC_Cnt = 0;
            gtReceived_Data.LowVoltage	    = gucRx_Buffer[4] >> 7;					              /*是否欠压，0-不欠压，1-欠压*/
            gtReceived_Data.Power	        = (uint16_t)gucRx_Buffer[6] << 8 | gucRx_Buffer[5];		/*控制器实时功率 单位:W*/
            gtReceived_Data.Speed_0_1Km	    = (uint16_t)gucRx_Buffer[8] << 8 | gucRx_Buffer[7];		/*整车速度*/
            gtReceived_Data.Ctrl_Soc	    = gucRx_Buffer[9]  ;			                        /*电池电量百分比*/
            gtReceived_Data.Wheel_Diameter	= (uint16_t)gucRx_Buffer[11] << 8 | gucRx_Buffer[10];	/*轮直径*/

            gtReceived_Data.ErrCode = gucRx_Buffer[13];
        }
        else if(gucRx_Buffer[2] == 'S') /*控制器发会S，表示接收到了配置帧*/
        {
            gucReceivedConfigFrame = 1;
        }
        else if(gucRx_Buffer[2] == 0x54) /*控制器发会S，表示接收到了里程帧*/
        {
            gtReceived_Data.Range = gucRx_Buffer[8] + gucRx_Buffer[9] * 256;
            gtReceived_Data.Odo   = gucRx_Buffer[4] | ((uint32_t)gucRx_Buffer[5] << 8) | ((uint32_t)gucRx_Buffer[6] << 16) | ((uint32_t)gucRx_Buffer[7] << 24);
        }
        else if(gucRx_Buffer[2] == 'D') /*控制器发D，表示接收到了应答帧*/
        {
            gtReceived_Data.Para_Addr = gucRx_Buffer[4] + gucRx_Buffer[5] * 256;
            switch(gtReceived_Data.Para_Addr)
            {
                case 0x8000:
                    gtReceived_Data.UUID[0] = gucRx_Buffer[6];     
                    gtReceived_Data.UUID[1] = gucRx_Buffer[7];  
                    gtReceived_Data.UUID[12] |= 0x01;      /*用来记录接收标志位*/           
                    break;
                case 0x8001:
                    gtReceived_Data.UUID[2] = gucRx_Buffer[6];     
                    gtReceived_Data.UUID[3] = gucRx_Buffer[7];   
                    gtReceived_Data.UUID[12] |= 0x02;                  
                    break;
                case 0x8002:
                    gtReceived_Data.UUID[4] = gucRx_Buffer[6];     
                    gtReceived_Data.UUID[5] = gucRx_Buffer[7];  
                    gtReceived_Data.UUID[12] |= 0x04;                 
                    break;
                case 0x8003:
                    gtReceived_Data.UUID[6] = gucRx_Buffer[6];     
                    gtReceived_Data.UUID[7] = gucRx_Buffer[7];  
                    gtReceived_Data.UUID[12] |= 0x08;                 
                    break;
                case 0x8004:
                    gtReceived_Data.UUID[8] = gucRx_Buffer[6];     
                    gtReceived_Data.UUID[9] = gucRx_Buffer[7]; 
                    gtReceived_Data.UUID[12] |= 0x10;                 
                    break;      
                case 0x8005:
                    gtReceived_Data.UUID[10] = gucRx_Buffer[6];     
                    gtReceived_Data.UUID[11] = gucRx_Buffer[7];  
                    gtReceived_Data.UUID[12] |= 0x20;
 
                    break;   
                
                case 0x891D:
                    gtReceived_Data.Unit = 1 - gucRx_Buffer[6] & 0x01;
                    if((gtReceived_Data.UUID[12] & 0x2F) == 0X2F)/*UUID 全部接收OK 再去做CRC 再去比较*/
                    {
                        CrcChecksum = CRC16(&gtReceived_Data.UUID[0],12);
                        if((gtParam.UUIDCrc != CrcChecksum) || (gtParam.MC_Unit != gtReceived_Data.Unit))/*更换了控制器 或者 更换了控制器的单位版本程序  都使用读取到的控制器单位*/
                        {
                            gtParam.UUIDCrc = CrcChecksum;
                            gtParam.MC_Unit = gtReceived_Data.Unit;
                            
                            gtParam.Unit = gtReceived_Data.Unit;
                            gucUnit = gtParam.Unit;
                            vParam_Write(&gtParam, ConfigInfo);   
                        } 
                    }
                    
                    break;
                case 0x891C:
                    gtParam.Class_type = gucRx_Buffer[6] & 0x03;
                    break;
                case 0x891E:
                    gtReceived_Data.Class_OptionMax = gucRx_Buffer[6] & 0x1f;
                    gucReceivedReadFrame = 1;    
                    break;                
                case 0x8A05:
                    gtReceived_Data.SoftVer[0] = gucRx_Buffer[6] + gucRx_Buffer[7] *256;
                    break;
                case 0x8A06:
                    gtReceived_Data.SoftVer[1] = gucRx_Buffer[6] + gucRx_Buffer[7] *256;
                    break;
                case 0x8A07:
                    gtReceived_Data.SoftVer[2] = gucRx_Buffer[6] + gucRx_Buffer[7] *256;
                    break;
                case 0x8A08:
                    gtReceived_Data.SoftVer[3] = gucRx_Buffer[6] + gucRx_Buffer[7] *256;
                    break;
                case 0x8A09:
                    gtReceived_Data.HardVer[0] = gucRx_Buffer[6] + gucRx_Buffer[7] *256;
                    break;
                case 0x8A0A:
                    gtReceived_Data.HardVer[1] = gucRx_Buffer[6] + gucRx_Buffer[7] *256;
                    break;
                default:
                    break;
            }
            if((gtParam.Class_type < 1) || (gtParam.Class_type > 5))
            {
                gtParam.Class_type = 1;
            }
//            if(gucClassType != gtParam.Class_type)   /*(gucUnit != gtParam.Unit) ||*/
//            {
//                gucUnit = gtParam.Unit;
                if(gucClassType != gtParam.Class_type)
                {
                    gucClassType = gtParam.Class_type;
                    gtParam.Handle_Speed_Limit = Handle_Limit_Class[gucClassType];
                    gtParam.Speed_Limit = Speed_Limit_Class[gucClassType];
                    vPROTOCOL_Set_Handle_Speed_Limit(gtParam.Handle_Speed_Limit);
                    vPROTOCOL_Set_Speed_Limit(gtParam.Speed_Limit);
                    vParam_Write(&gtParam, ConfigInfo);                    
                }
                
//            }

        }

    }

    return;
}

void vPROTOCOL_Updata_Speed_Limit(void)
{
    //   if(gucClassType != gtParam.Class_type)
    {
        gtParam.Handle_Speed_Limit = Handle_Limit_Class[gtParam.Class_type];
        gtParam.Speed_Limit = Speed_Limit_Class[gtParam.Class_type];
    }
}
/******************************************************************************
** 功  能：发送5S协议数据
** 参  数：无
** 返回值：无
** 备  注：该函数500ms调用一次
******************************************************************************/

static void vPROTOCOL_Send_LiShui_Uart(void)
{
    uint16_t lucChecksum = 0;
    static uint8_t ucParaSentCnt = 0;
    //    static uint8_t ucParaWritCnt = 0;
    //    static uint8_t  lucSendPwm = 0;
    //    static uint16_t  lucPushPwm = 100;
    static uint8_t lucOverSpeed = 0;/*超速标志*/
    uint8_t n;
    uint16_t luc_Speed_Limit = 0;    /*限速值*/
    //    uint16_t luc_Handle_Speed_Limit= 0;     /*转把限速值*/
    uint8_t Key_array[2];

    switch(geSend_Data_Type)
    {
    case Send_Stop:
    {
        return;						/*停止发送，直接退出*/
    }
    case Send_Run_Data:
    case Send_Config_RunData_OneTime:
    {
        /*获取当前电压并和欠压值对比，低于欠压值，置位欠压标志位*/
        if(ulGet_Sys_Voltage() < gtSend_Data.Low_Voltage * 100)
        {
            gtSend_Data.Battery_Low = 1;
        }
        else
        {
            gtSend_Data.Battery_Low = 0;
        }
        gucTx_Buffer[0] = 0x3A;     /*帧头*/
        gucTx_Buffer[1] = 0x1A;     /*从机地址*/
        if(Run_Read_Flag >= 1)
        {
            Run_Read_Flag = 0;
            gucTx_Buffer[2] = 0x54;		/*正常工作数据，帧头标志是54*/
            gucTx_Buffer[3] = 0x02;     /*数据长度，固定为2*/
            gucTx_Buffer[4] = gtParam.Class_type;
            gucTx_Buffer[5] = 0;
        }
        else
        {
            Run_Read_Flag++;
            gucTx_Buffer[2] = 'R';		/*正常工作数据，帧头标志是R*/
            gucTx_Buffer[3] = 0x02;     /*数据长度，固定为2*/

            gucTx_Buffer[4] = gtSend_Data.Pas; /*助推时发送助推的PWM值，除以2是为了每2次变化1*/
            /*bit7:大灯状态，bit5:欠压标志，bit4：助推功能 bit3：是否在设置界面  bit2：右转灯 bit1：左转灯*/
            gucTx_Buffer[5] = (gtSend_Data.Lamp << 7)  | (gtSend_Data.Battery_Low << 5) | (gtSend_Data.Push << 4) | (gulIsInSetting << 3) | (gtSend_Data.Turn_Light_Right << 2) | (gtSend_Data.Turn_Light_Left << 1);
        }

        luc_Speed_Limit = gtParam.Speed_Limit;
        /*判断是否超速*/
        if((usPROTOCOL_Get_Speed() > luc_Speed_Limit * 10) && ((NO_LIMIT_WHEN_MAX == 0) || ((NO_LIMIT_WHEN_MAX == 1) && (luc_Speed_Limit != CONFIG_SPEED_MAX * 10))))
        {
            lucOverSpeed = 1;
        }
        else
        {
            /*速度降低到限速值-1以下时，清超速标志*/
            if(usPROTOCOL_Get_Speed() < (gtSend_Data.Speed_Limit_Assist - 1) * 10)
            {
                lucOverSpeed = 0;
                //                      lucSendPwm = gtSend_Data.Max_PWM;/*当速度值低于限速值-1时，恢复档位的PWM值*/ /*5S协议，超速后不再要求降PWM*/
            }
        }

        if(lucOverSpeed == 1)
        {
            gucTx_Buffer[5] |= 0x01;    /*bit0:置位超速标志*/
        }
        else
        {
            gucTx_Buffer[5] &= 0xFE;    /*bit0:清超速标志*/
        }

        /*计算校验值，从gucTx_Buffer[1]开始计算*/
        for(n = 1; n < 6; n++)
        {
            lucChecksum += gucTx_Buffer[n];
        }

        /*填充校验值以及帧尾*/
        gucTx_Buffer[6] = lucChecksum % 256;
        gucTx_Buffer[7] = lucChecksum / 256;
        gucTx_Buffer[8] = 0x0D;
        gucTx_Buffer[9] = 0x0A;

        break;
    }
    case Send_Config_Data:
    case Send_Config_Data_OneTime:
    {
        gucTx_Buffer[0] = 0x3A;     /*帧头*/
        gucTx_Buffer[1] = 0x1A;     /*从机地址*/
        gucTx_Buffer[2] = 'S';		/*设置数据，帧头标志是S*/
        gucTx_Buffer[3] = 0x0A;     /*数据长度，10*/

        /*bit6：助力信号方向，bit5-0：助力强度（过几个磁钢开始）*/
        gucTx_Buffer[4] = ((gtSend_Data.Assistant_Dir & 0x01) << 6) | (gtSend_Data.Assistant_Sensitivity & 0x3F);

        /*助力磁钢数*/
        gucTx_Buffer[5] = 768UL / gtSend_Data.Assistant_Num;

        /*bit7:转把是否分档，bit6：转把是否有助推，bit5-4：缓启动参数，bit3-0：速度传感器磁钢数*/
        gucTx_Buffer[6] = ((gtSend_Data.Handle_Segement & 0x01) << 7) | ((gtSend_Data.Handle_Push & 0x01) << 6) | ((gtSend_Data.Start_Strength & 0x03) << 4) | (gtSend_Data.Speed_Sensor_Num & 0x0F);


        switch(gtSend_Data.Sys_Voltage)
        {
        case 24:    /*系统电压24V，欠压基准值21.0V*/
        {
            if(gtSend_Data.Low_Voltage < 210)
            {
                gucTx_Buffer[7] = ((210 - gtSend_Data.Low_Voltage) & 0x7F) | 0x80;
            }
            else
            {
                gucTx_Buffer[7] = gtSend_Data.Low_Voltage - 210;
            }
            /*系统电压和限流数据*/
            gucTx_Buffer[8] = 0x40 | (gtSend_Data.Current_Limit / 5);
            break;
        }
        case 36:    /*系统电压36V，欠压基准值31.5V*/
        {
            if(gtSend_Data.Low_Voltage < 315)
            {
                gucTx_Buffer[7] = ((315 - gtSend_Data.Low_Voltage) & 0x7F) | 0x80;
            }
            else
            {
                gucTx_Buffer[7] = gtSend_Data.Low_Voltage - 315;
            }
            /*系统电压和限流数据*/
            gucTx_Buffer[8] = 0x80 | (gtSend_Data.Current_Limit / 5);
            break;
        }
        case 48:    /*系统电压48V，欠压基准值42.0V*/
        {
            if(gtSend_Data.Low_Voltage < 420)
            {
                gucTx_Buffer[7] = ((420 - gtSend_Data.Low_Voltage) & 0x7F) | 0x80;
            }
            else
            {
                gucTx_Buffer[7] = gtSend_Data.Low_Voltage - 420;
            }
            /*系统电压和限流数据*/
            gucTx_Buffer[8] = 0xC0 | (gtSend_Data.Current_Limit / 5);
            break;
        }
        }

        gucTx_Buffer[9] = 0;    /*随机数，握手用，0-63*/

        /*Byte 10 助力限速值*/
        gucTx_Buffer[10] = gtSend_Data.Speed_Limit_Assist;  //luc_Speed_Limit;//
        /*Byte 11 转把限速值*/
        gucTx_Buffer[11] = gtSend_Data.Speed_Limit_Handle; //luc_Handle_Speed_Limit;//
        /*Byte 12(低) Byte 13(高)   bit0~30轮直径 bit 31 保存标志*/
        gucTx_Buffer[12] = gtSend_Data.Wheel_Diameter  & 0XFF;
        gucTx_Buffer[13] = (gtSend_Data.IsSaveFlg << 7) | (gtSend_Data.Wheel_Diameter >> 8) ;

        /*计算校验值，从gucTx_Buffer[1]开始计算*/
        for(n = 1; n < 14; n++)
        {
            lucChecksum += gucTx_Buffer[n];
        }

        /*填充校验值以及帧尾*/
        gucTx_Buffer[14] = lucChecksum % 256;
        gucTx_Buffer[15] = lucChecksum / 256;
        gucTx_Buffer[16] = 0x0D;
        gucTx_Buffer[17] = 0x0A;
        break;
    }
    /*参数读取*/
    case Send_Parameter_Data_Read:
    {

        gucTx_Buffer[0] = 0x3A;     /*帧头*/
        gucTx_Buffer[1] = 0x1A;     /*从机地址*/
        gucTx_Buffer[2] = 'D';		/*设置数据，帧头标志是D  Display读命令*/
        gucTx_Buffer[3] = 0x02;     /*数据长度，2*/
        gucTx_Buffer[4] = gusParaAddrTable[ucParaSentCnt % (sizeof(gusParaAddrTable) / 2) ] &  0xff;  /*被读参数的地址 低八位*/
        gucTx_Buffer[5] = gusParaAddrTable[ucParaSentCnt % (sizeof(gusParaAddrTable) / 2)] >> 8;    /*被读参数的地址 高八位*/

        /*计算校验值，从gucTx_Buffer[1]开始计算*/
        for(n = 1; n < 6; n++)
        {
            lucChecksum += gucTx_Buffer[n];
        }
        /*填充校验值以及帧尾*/
        gucTx_Buffer[6] = lucChecksum % 256;
        gucTx_Buffer[7] = lucChecksum / 256;
        gucTx_Buffer[8] = 0x0D;
        gucTx_Buffer[9] = 0x0A;

        gucParaReadOnCnt++;
        ucParaSentCnt ++;
        if(ucParaSentCnt >= (sizeof(gusParaAddrTable) / 2)  )
        {
            if(gucReceivedReadFrame || (gucParaReadOnCnt > 12))
            {
                vPROTOCOL_Send_Config_Data_OneTime();
            }
            else
            {
                ucParaSentCnt = 0;
            }
        }
        break;
    }
    case Send_Key_Requiest:
    {
        gucTx_Buffer[0] = 0x3A;     /*帧头*/
        gucTx_Buffer[1] = 0x51;     /*从机地址*/
        gucTx_Buffer[2] = 0x7F;		/*固定数*/
        gucTx_Buffer[3] = 0x08;     /*固定数*/
        gucTx_Buffer[4] = 0xDB;		/*固定数*/
        gucTx_Buffer[5] = 0x7C;     /*固定数*/
        gucTx_Buffer[6] = 0x0D;		/*固定数*/
        gucTx_Buffer[7] = 0x0A;     /*固定数*/
        break;
    }
    /*参数写入*/
    case Send_Parameter_Data_Write:
    {
        gucTx_Buffer[0] = 0x3A;     /*帧头*/
        gucTx_Buffer[1] = 0x53;     /*从机地址*/

        /*加密*/
        {
            Key_array[0] = Key1;
            Key_array[1] = Key3;

            gucTx_Buffer[2] = 0x89 ^ (CRC16(Key_array, 2) >> 8) ^ 0x7D;		/*地址高*/
            gucTx_Buffer[3] = 0x1D ^ (CRC16(Key_array, 2) & 0xFF) ^ 0x9B; /*地址低*/

            Key_array[0] = Key2;
            Key_array[1] = Key4;

            gucTx_Buffer[4] = 0x00 ^ (CRC16(Key_array, 2) >> 8) ^ 0x54;		/*数据高*/
            gucTx_Buffer[5] = (1- gtParam.Unit) ^ (CRC16(Key_array, 2) & 0xFF) ^ 0x3E; /*数据低*/
            //                ucParaWritCnt = 0;
        }

        lucChecksum = CRC16(gucTx_Buffer, 6);
        gucTx_Buffer[6] = lucChecksum / 256;		/*校验高*/
        gucTx_Buffer[7] = lucChecksum & 0xFF;     /*校验低*/
        gucTx_Buffer[8] = 0x0D;		/*结束符*/
        gucTx_Buffer[9] = 0x0A;     /*结束符*/
        break;
    }
    case Send_Parameter_Out:
    {
        gucTx_Buffer[0] = 0x3A;     /*帧头*/
        gucTx_Buffer[1] = 0x50;     /*从机地址*/
        gucTx_Buffer[2] = 0x7F;		/*固定数*/
        gucTx_Buffer[3] = 0x08;     /*固定数*/
        gucTx_Buffer[4] = 0x1B;		/*固定数*/
        gucTx_Buffer[5] = 0x2D;     /*固定数*/
        gucTx_Buffer[6] = 0x0D;		/*固定数*/
        gucTx_Buffer[7] = 0x0A;     /*固定数*/

        break;
    }
    /*关机参数写*/
    case Send_Poweroff_Write:
    {
        gucTx_Buffer[0] = 0x3A;     /*帧头*/
        gucTx_Buffer[1] = 0x1A;     /*从机地址*/
        gucTx_Buffer[2] = 0x55;		/*设置数据，帧头标志是D  Display读命令*/
        gucTx_Buffer[3] = 0x02;     /*数据长度，2*/
        gucTx_Buffer[4] = 0x1E;     /*被读参数的地址 低八位*/
        gucTx_Buffer[5] = 0x89;     /*被读参数的地址 高八位*/
        gucTx_Buffer[6] = 0x00;     /*被读参数的地址 低八位*/
        gucTx_Buffer[7] = 0x00;     /*被读参数的地址 高八位*/

        /*计算校验值，从gucTx_Buffer[1]开始计算*/
        for(n = 1; n < 8; n++)
        {
            lucChecksum += gucTx_Buffer[n];
        }
        /*填充校验值以及帧尾*/
        gucTx_Buffer[8] = lucChecksum % 256;
        gucTx_Buffer[9] = lucChecksum / 256;
        gucTx_Buffer[10] = 0x0D;
        gucTx_Buffer[11] = 0x0A;

        break;
    }

    }
    if(geSend_Data_Type == Send_Parameter_Data_Write)
    {
        USART_MCU_Send_Frame(gucTx_Buffer, 10);		/*发送数据*/
    }
    else if(geSend_Data_Type == Send_Poweroff_Write)
    {
        USART_MCU_Send_Frame(gucTx_Buffer, 12);		/*发送数据*/
    }
    else if(geSend_Data_Type >= Send_Key_Requiest)
    {
        USART_MCU_Send_Frame(gucTx_Buffer, 8);		/*发送数据*/
    }
    else
    {
        USART_MCU_Send_Frame(gucTx_Buffer, gucTx_Buffer[3] + 8);		/*发送数据*/
    }

    if(geSend_Data_Type == Send_Parameter_Out)
    {
        vPROTOCOL_Send_Config_Data_OneTime();
    }
    /*如果请求发送配置帧标记有效，则更改发送状态，下一次即开始发送配置帧*/
    if(gucRequestSendConfigData == 1)
    {
        gucRequestSendConfigData = 0;
        geSend_Data_Type = Send_Config_Data;
    }

    /*如果状态标记为只发送一次配置数据，那么发送完配置数据，并检测控制器已收到，将状态标记为发送运行数据*/
    if(geSend_Data_Type == Send_Config_Data_OneTime)
    {
        if(gucReceivedConfigFrame == 1)
        {
            geSend_Data_Type = Send_Run_Data;
            gucReceivedConfigFrame = 0;
        }
    }
    /*如果状态标记为 设置界面只发送一次运行数据，那么发送完运行数据，并检测控制器已收到，将状态标记为发送配置数据*/
    if(geSend_Data_Type == Send_Config_RunData_OneTime)
    {
        if(gulReceivedRunFrame >= 2)/*接收到2次回复*/
        {
            geSend_Data_Type = Send_Config_Data;
            gulReceivedRunFrame = 0;
        }
    }
    
}

/******************************************************************************
** 功  能：读取固件零件号 函数
** 参  数： 
** 返回值：无
** 备  注：只轮询 读取一遍
** 适用协议： 
******************************************************************************/

void vPROTOCOL_Read_Firmware_Part_Number(void)
{
    uint8_t n = 0;
    uint16_t lucChecksum = 0;
    
    
    gucTx_Buffer[0] = 0x3A;     /*帧头*/
    gucTx_Buffer[1] = 0x1A;     /*从机地址*/
    gucTx_Buffer[2] = 'D';		/*设置数据，帧头标志是D  Display读命令*/
    gucTx_Buffer[3] = 0x02;     /*数据长度，2*/
    gucTx_Buffer[4] = luVerAddr &  0xff;  /*被读参数的地址 低八位*/
    gucTx_Buffer[5] = luVerAddr >> 8;    /*被读参数的地址 高八位*/

    /*计算校验值，从gucTx_Buffer[1]开始计算*/
    for(n = 1; n < 6; n++)
    {
        lucChecksum += gucTx_Buffer[n];
    }
    /*填充校验值以及帧尾*/
    gucTx_Buffer[6] = lucChecksum % 256;
    gucTx_Buffer[7] = lucChecksum / 256;
    gucTx_Buffer[8] = 0x0D;
    gucTx_Buffer[9] = 0x0A;
    
    USART_MCU_Send_Frame(gucTx_Buffer, gucTx_Buffer[3] + 8);		/*发送数据*/
    
    if(++luVerAddr>0x8A0A)
    {
        luVerAddr = 0x8A05;
        luRead_Ver_flag = 0;
    }
}

/******************************************************************************
** 功  能：是否读取 固件零件号
** 参  数：in_out    1 开始读取  0 停止读取
** 返回值：无
** 备  注：
** 适用协议： 
******************************************************************************/

void vPROTOCOL_Read_version(uint8_t in_out)
{
    if(in_out)
    {
        luVerAddr = 0x8A05;
        luRead_Ver_flag = 1;         
    }
    else
    {
        luVerAddr = 0x8A05;
        luRead_Ver_flag = 0;
    }
}
    
/******************************************************************************
** 功  能：复位通信超时计数变量
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_ResetCommunicationOverTime(void)
{
    __disable_irq();
    gucTimeOutError = 0;
    gulCommunicationCnt = ulBsp_Getticks();
    __enable_irq();

}


/******************************************************************************
** 功  能：开机上电时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_PowerOn(void)
{
    vPROTOCOL_Set_Wheel(usGet_Wheel_Size(gtParam.Wheel_Diameter));  /*轮径，为和其他协议兼容，轮径是×10以后的值*/
    vPROTOCOL_Set_Pas(1);                                           /*开机LOGO界面发0档*/
    vPROTOCOL_Set_Lamp(gucLamp);
    vPROTOCOL_Set_Speed_Limit(gtParam.Speed_Limit);                 /*限速*/
    vPROTOCOL_Set_Handle_Speed_Limit(gtParam.Handle_Speed_Limit);   /*转把限速*/
    vPROTOCOL_Set_Assistant_Dir(CONFIG_ASSISTANT_DIR);              /*助力方向*/
    vPROTOCOL_Set_Assistant_Num(gtParam.Assistant_Num);             /*助力磁钢数*/
    vPROTOCOL_Set_Assistant_Sensitivity(gtParam.Sensitivity);       /*助力灵敏度*/
    vPROTOCOL_Set_Current_Limit(gtParam.Current_Limit);             /*限流值*/
    vPROTOCOL_Set_Handle_Push(gtParam.Throttle_6KM);                /*是否转把助推*/
    vPROTOCOL_Set_Handle_Segement(gtParam.Throttle_PAS);            /*转把是否分档*/
    vPROTOCOL_Set_Sys_Voltage(gtParam.Volt);                        /*系统电压值*/
    vPROTOCOL_Set_Speed_Sensor_Num(gtParam.Speed_Sensor_Num);       /*速度磁钢数*/
    vPROTOCOL_Set_Start_Strength(gtParam.Start_Strength);           /*助力启动强度*/
    vPROTOCOL_Send_Read_Data_OneTime();                             /*开机时发送读取参数数据，然后切换为发送一次配置数据，然后自动切换为发送运行数据*/
}

/******************************************************************************
** 功  能：退出设置时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_ExitSetting(void)
{
    vPROTOCOL_Set_Wheel(usGet_Wheel_Size(gtParam.Wheel_Diameter));  /*轮径，为和其他协议兼容，轮径是×10以后的值*/
    vPROTOCOL_Set_Speed_Limit(gtParam.Speed_Limit);                 /*限速*/
    vPROTOCOL_Set_Handle_Speed_Limit(gtParam.Handle_Speed_Limit);   /*转把限速*/
    vPROTOCOL_Set_Assistant_Dir(CONFIG_ASSISTANT_DIR);              /*助力方向*/
    vPROTOCOL_Set_Assistant_Num(gtParam.Assistant_Num);             /*助力磁钢数*/
    vPROTOCOL_Set_Assistant_Sensitivity(gtParam.Sensitivity);       /*助力灵敏度*/
    vPROTOCOL_Set_Current_Limit(gtParam.Current_Limit);             /*限流值*/
    vPROTOCOL_Set_Handle_Push(gtParam.Throttle_6KM);                /*是否转把助推*/
    vPROTOCOL_Set_Handle_Segement(gtParam.Throttle_PAS);            /*转把是否分档*/
    vPROTOCOL_Set_Sys_Voltage(gtParam.Volt);                        /*系统电压值*/
    vPROTOCOL_Set_Speed_Sensor_Num(gtParam.Speed_Sensor_Num);       /*速度磁钢数*/
    vPROTOCOL_Set_Start_Strength(gtParam.Start_Strength);           /*助力启动强度*/
    //    if(gucUnit != gtParam.Unit)//((gucClassType != gtParam.Class_type) || )  /*不再发送*/
//    {
//        geSend_Data_Type = Send_Key_Requiest;
//        gucUnit = gtParam.Unit;
//        //        gucClassType = gtParam.Class_type;
//    }
//    else
        vPROTOCOL_Send_Config_Data_OneTime();                           /*开机时发送一次配置数据，然后自动切换为发送运行数据*/
}

